home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / ncurses / base / vsscanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  8.4 KB  |  357 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  State-machine fallback written by Thomas E. Dickey 2002                 *
  31.  ****************************************************************************/
  32.  
  33. /*
  34.  * This function is needed to support vwscanw
  35.  */
  36.  
  37. #include <curses.priv.h>
  38.  
  39. #if !HAVE_VSSCANF
  40.  
  41. MODULE_ID("$Id: vsscanf.c,v 1.16 2002/09/07 17:27:56 tom Exp $")
  42.  
  43. #if !(HAVE_VFSCANF || HAVE__DOSCAN)
  44.  
  45. #include <ctype.h>
  46.  
  47. #define L_SQUARE '['
  48. #define R_SQUARE ']'
  49.  
  50. typedef enum {
  51.     cUnknown
  52.     ,cError            /* anything that isn't ANSI */
  53.     ,cAssigned
  54.     ,cChar
  55.     ,cInt
  56.     ,cFloat
  57.     ,cDouble
  58.     ,cPointer
  59.     ,cLong
  60.     ,cShort
  61.     ,cRange
  62.     ,cString
  63. } ChunkType;
  64.  
  65. typedef enum {
  66.     oUnknown
  67.     ,oShort
  68.     ,oLong
  69. } OtherType;
  70.  
  71. typedef enum {
  72.     sUnknown
  73.     ,sPercent            /* last was '%' beginning a format */
  74.     ,sNormal            /* ...somewhere in the middle */
  75.     ,sLeft            /* last was left square bracket beginning a range */
  76.     ,sRange            /* ...somewhere in the middle */
  77.     ,sFinal            /* last finished a format */
  78. } ScanState;
  79.  
  80. static ChunkType
  81. final_ch(int ch, OtherType other)
  82. {
  83.     ChunkType result = cUnknown;
  84.  
  85.     switch (ch) {
  86.     case 'c':
  87.     if (other == oUnknown)
  88.         result = cChar;
  89.     else
  90.         result = cError;
  91.     break;
  92.     case 'd':
  93.     case 'i':
  94.     case 'X':
  95.     case 'x':
  96.     switch (other) {
  97.     case oUnknown:
  98.         result = cInt;
  99.         break;
  100.     case oShort:
  101.         result = cShort;
  102.         break;
  103.     case oLong:
  104.         result = cLong;
  105.         break;
  106.     }
  107.     break;
  108.     case 'E':
  109.     case 'e':
  110.     case 'f':
  111.     case 'g':
  112.     switch (other) {
  113.     case oUnknown:
  114.         result = cFloat;
  115.         break;
  116.     case oShort:
  117.         result = cError;
  118.         break;
  119.     case oLong:
  120.         result = cDouble;
  121.         break;
  122.     }
  123.     break;
  124.     case 'n':
  125.     if (other == oUnknown)
  126.         result = cAssigned;
  127.     else
  128.         result = cError;
  129.     break;
  130.     case 'p':
  131.     if (other == oUnknown)
  132.         result = cPointer;
  133.     else
  134.         result = cError;
  135.     break;
  136.     case 's':
  137.     if (other == oUnknown)
  138.         result = cString;
  139.     else
  140.         result = cError;
  141.     break;
  142.     }
  143.     return result;
  144. }
  145.  
  146. static OtherType
  147. other_ch(int ch)
  148. {
  149.     OtherType result = oUnknown;
  150.     switch (ch) {
  151.     case 'h':
  152.     result = oShort;
  153.     break;
  154.     case 'l':
  155.     result = oLong;
  156.     break;
  157.     }
  158.     return result;
  159. }
  160. #endif
  161.  
  162. /*VARARGS2*/
  163. NCURSES_EXPORT(int)
  164. vsscanf(const char *str, const char *format, va_list ap)
  165. {
  166. #if HAVE_VFSCANF || HAVE__DOSCAN
  167.     /*
  168.      * This code should work on anything descended from AT&T SVr1.
  169.      */
  170.     FILE strbuf;
  171.  
  172.     strbuf._flag = _IOREAD;
  173.     strbuf._ptr = strbuf._base = (unsigned char *) str;
  174.     strbuf._cnt = strlen(str);
  175.     strbuf._file = _NFILE;
  176.  
  177. #if HAVE_VFSCANF
  178.     return (vfscanf(&strbuf, format, ap));
  179. #else
  180.     return (_doscan(&strbuf, format, ap));
  181. #endif
  182. #else
  183.     static int can_convert = -1;
  184.  
  185.     int assigned = 0;
  186.     int consumed = 0;
  187.  
  188.     T((T_CALLED("vsscanf(%s,%s,...)"),
  189.        _nc_visbuf2(1, str),
  190.        _nc_visbuf2(2, format)));
  191.  
  192.     /*
  193.      * This relies on having a working "%n" format conversion.  Check if it
  194.      * works.  Only very old C libraries do not support it.
  195.      *
  196.      * FIXME: move this check into the configure script.
  197.      */
  198.     if (can_convert < 0) {
  199.     int check1;
  200.     int check2;
  201.     if (sscanf("123", "%d%n", &check1, &check2) > 0
  202.         && check1 == 123
  203.         && check2 == 3) {
  204.         can_convert = 1;
  205.     } else {
  206.         can_convert = 0;
  207.     }
  208.     }
  209.  
  210.     if (can_convert) {
  211.     size_t len_fmt = strlen(format) + 32;
  212.     char *my_fmt = malloc(len_fmt);
  213.     ChunkType chunk, ctest;
  214.     OtherType other, otest;
  215.     ScanState state;
  216.     unsigned n;
  217.     int eaten;
  218.     void *pointer;
  219.  
  220.     if (my_fmt != 0) {
  221.         /*
  222.          * Split the original format into chunks, adding a "%n" to the end
  223.          * of each (except of course if it used %n), and use that
  224.          * information to decide where to start scanning the next chunk.
  225.          *
  226.          * FIXME:  does %n count bytes or characters?  If the latter, this
  227.          * will require further work for multibyte strings.
  228.          */
  229.         while (*format != '\0') {
  230.         /* find a chunk */
  231.         state = sUnknown;
  232.         chunk = cUnknown;
  233.         other = cUnknown;
  234.         pointer = 0;
  235.         for (n = 0; format[n] != 0 && state != sFinal; ++n) {
  236.             my_fmt[n] = format[n];
  237.             switch (state) {
  238.             case sUnknown:
  239.             if (format[n] == '%')
  240.                 state = sPercent;
  241.             break;
  242.             case sPercent:
  243.             if (format[n] == '%') {
  244.                 state = sUnknown;
  245.             } else if (format[n] == L_SQUARE) {
  246.                 state = sLeft;
  247.             } else {
  248.                 state = sNormal;
  249.                 --n;
  250.             }
  251.             break;
  252.             case sLeft:
  253.             state = sRange;
  254.             if (format[n] == '^') {
  255.                 ++n;
  256.                 my_fmt[n] = format[n];
  257.             }
  258.             break;
  259.             case sRange:
  260.             if (format[n] == R_SQUARE) {
  261.                 state = sFinal;
  262.                 chunk = cRange;
  263.             }
  264.             break;
  265.             case sNormal:
  266.             if (format[n] == '*') {
  267.                 state = sUnknown;
  268.             } else {
  269.                 if ((ctest = final_ch(format[n], other)) != cUnknown) {
  270.                 state = sFinal;
  271.                 chunk = ctest;
  272.                 } else if ((otest = other_ch(format[n])) != oUnknown) {
  273.                 other = otest;
  274.                 } else if (isalpha(format[n])) {
  275.                 state = sFinal;
  276.                 chunk = cError;
  277.                 }
  278.             }
  279.             break;
  280.             case sFinal:
  281.             break;
  282.             }
  283.         }
  284.         my_fmt[n] = '\0';
  285.         format += n;
  286.  
  287.         if (chunk == cUnknown
  288.             || chunk == cError) {
  289.             if (assigned == 0)
  290.             assigned = EOF;
  291.             break;
  292.         }
  293.  
  294.         /* add %n, if the format was not that */
  295.         if (chunk != cAssigned) {
  296.             strcat(my_fmt, "%n");
  297.         }
  298.  
  299.         switch (chunk) {
  300.         case cAssigned:
  301.             strcat(my_fmt, "%n");
  302.             pointer = &eaten;
  303.             break;
  304.         case cInt:
  305.             pointer = va_arg(ap, int *);
  306.             break;
  307.         case cShort:
  308.             pointer = va_arg(ap, short *);
  309.             break;
  310.         case cFloat:
  311.             pointer = va_arg(ap, float *);
  312.             break;
  313.         case cDouble:
  314.             pointer = va_arg(ap, double *);
  315.             break;
  316.         case cLong:
  317.             pointer = va_arg(ap, long *);
  318.             break;
  319.         case cPointer:
  320.             pointer = va_arg(ap, void *);
  321.             break;
  322.         case cChar:
  323.         case cRange:
  324.         case cString:
  325.             pointer = va_arg(ap, char *);
  326.             break;
  327.         case cError:
  328.         case cUnknown:
  329.             break;
  330.         }
  331.         /* do the conversion */
  332.         T(("...converting chunk #%d type %d(%s,%s)",
  333.            assigned + 1, chunk,
  334.            _nc_visbuf2(1, str + consumed),
  335.            _nc_visbuf2(2, my_fmt)));
  336.         if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0)
  337.             consumed += eaten;
  338.         else
  339.             break;
  340.         ++assigned;
  341.         }
  342.         free(my_fmt);
  343.     }
  344.     }
  345.     returnCode(assigned);
  346. #endif
  347. }
  348. #else
  349. extern
  350. NCURSES_EXPORT(void)
  351. _nc_vsscanf(void);        /* quiet's gcc warning */
  352. NCURSES_EXPORT(void)
  353. _nc_vsscanf(void)
  354. {
  355. }                /* nonempty for strict ANSI compilers */
  356. #endif /* !HAVE_VSSCANF */
  357.